﻿using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using Microsoft.SharePoint;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Drawing = DocumentFormat.OpenXml.Drawing;


namespace DemoOpenXMLPPT
{
    class Program
    {
        private const string url = "http://spvm/sites/demoopenxml";
        static void Main(string[] args)
        {
            Console.WriteLine("/*Génération Document PowerPoint Sample*/\n");
            GenerateDocument();
            Console.WriteLine("/*Fin*/\n");
            Console.ReadKey();
        }

        private static void GenerateDocument()
        {
            Stream docstream = null;
            using (SPSite site = new SPSite(url))
            {
                SPWeb web = site.OpenWeb();
                SPFile spf = web.GetFile("Shared Documents/PPT_TEMPLATE.pptx");
                if (!spf.Exists)
                {
                    Console.WriteLine("Le Document n'éxiste pas\n");
                }
                else
                { 
                    docstream = spf.OpenBinaryStream(); 
                }
                if (docstream != null)
                {
                    Console.WriteLine("Début de la phase de PowerPointProcessing\n");
                    using (PresentationDocument outDoc = PresentationDocument.Open(docstream, true))
                    {
                        
                        int slideinjectionid = 2;//Point de départ de notre injection
                        PresentationPart part = outDoc.PresentationPart;
                        OpenXmlElementList slideIds = part.Presentation.SlideIdList.ChildElements;//récupération des ID de toutes les slides
                        SPList spList = web.Lists.TryGetList("demo");
                        if (spList != null)
                        {
                            SPQuery qry = new SPQuery();
                            qry.ViewFields = @"<FieldRef Name='Title' /><FieldRef Name='Description' />";
                            
                            List<SPListItem> listItemsBatch = spList.GetItems(qry).Cast<SPListItem>().ToList();
                            for (int j = 0; j < listItemsBatch.Count; j++)//A chaque saut contenant notre batch de données, on créé une nouvelle slide
                            {
                                var fiveitems = listItemsBatch.Skip(j * 5).Take(5); //Saut de 5 en 5

                                int v = fiveitems.Count();
                                if (v != 0 && v <= 5)
                                {
                                    int idslide;
                                    InsertNewSlide(outDoc, slideinjectionid, "MA SLIDE INJECTEE");//Insert une slide

                                    idslide = slideinjectionid; //récupération de la nouvelle slide pour la passer en courante
                                    string currentrelID = (slideIds[idslide++] as SlideId).RelationshipId;
                                    SlidePart currentSlide = (SlidePart)part.GetPartById(currentrelID);

                                    //remplissage du tableau
                                    foreach (SPListItem item in fiveitems)
                                    {
                                        Drawing.Table tbl = currentSlide.Slide.Descendants<Drawing.Table>().First();
                                        Drawing.TableRow tr = new Drawing.TableRow();
                                        tr.Height = 60;//Important sinon erreur de génération PowerPoint !
                                        tr.Append(CreateTextCell(item["Title"] as string));
                                        tr.Append(CreateTextCell(item["Description"] as string));
                                        tbl.Append(tr);
                                    }
                                    slideinjectionid++;//Incrément pour la slide suivante
                                }
                            }
                            
                        }

                    }
                    CREATE_OUTPUT_DOC(web, docstream, "OUT_PPT_TEMPLATE", ".pptx");
                }
            }
        }


        // Insertion d'une slide avec un numéro et un titre
        public static void InsertNewSlide(PresentationDocument presentationDocument, int position, string slideTitle)
        {

            if (presentationDocument == null)
            {
                throw new ArgumentNullException("presentationDocument");
            }

            if (slideTitle == null)
            {
                throw new ArgumentNullException("slideTitle");
            }

            PresentationPart presentationPart = presentationDocument.PresentationPart;

            // Verify that the presentation is not empty.
            if (presentationPart == null)
            {
                throw new InvalidOperationException("The presentation document is empty.");
            }

           
            GeneratedClass mygeneratedclass = new GeneratedClass();//Instanciation de ma classe aveec mon tableau
           
            Slide slide = mygeneratedclass.GenerateSlide();//Attachement de ma classe générée 


            uint drawingObjectId = 1;

            // Declare and instantiate the title shape of the new slide.
            Shape titleShape = slide.CommonSlideData.ShapeTree.AppendChild(new Shape());

            drawingObjectId++;

            // Specify the required shape properties for the title shape. 
            titleShape.NonVisualShapeProperties = new NonVisualShapeProperties
                (new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Title" },
                new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
                new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Type = PlaceholderValues.Title }));
            titleShape.ShapeProperties = new ShapeProperties();

            // Specify the text of the title shape.
            titleShape.TextBody = new TextBody(new Drawing.BodyProperties(),
                    new Drawing.ListStyle(),
                    new Drawing.Paragraph(new Drawing.Run(new Drawing.Text() { Text = slideTitle })));

            // Declare and instantiate the body shape of the new slide.
            Shape bodyShape = slide.CommonSlideData.ShapeTree.AppendChild(new Shape());
            drawingObjectId++;

            // Specify the required shape properties for the body shape.
            bodyShape.NonVisualShapeProperties = new NonVisualShapeProperties(new NonVisualDrawingProperties() { Id = drawingObjectId, Name = "Content Placeholder" },
                    new NonVisualShapeDrawingProperties(new Drawing.ShapeLocks() { NoGrouping = true }),
                    new ApplicationNonVisualDrawingProperties(new PlaceholderShape() { Index = 1 }));
            bodyShape.ShapeProperties = new ShapeProperties();

            // Specify the text of the body shape.
            bodyShape.TextBody = new TextBody(new Drawing.BodyProperties(),
                    new Drawing.ListStyle(),
                    new Drawing.Paragraph());

            // Create the slide part for the new slide.
            SlidePart slidePart = presentationPart.AddNewPart<SlidePart>();

            // Création de la nouvelle slide
            slide.Save(slidePart);

          
            SlideIdList slideIdList = presentationPart.Presentation.SlideIdList;

            uint maxSlideId = 1;
            SlideId prevSlideId = null;

            foreach (SlideId slideId in slideIdList.ChildElements)
            {
                if (slideId.Id > maxSlideId)
                {
                    maxSlideId = slideId.Id;
                }

                position--;
                if (position == 0)
                {
                    prevSlideId = slideId;
                }

            }

            maxSlideId++;

            // Get the ID of the previous slide.
            SlidePart lastSlidePart;

            if (prevSlideId != null)
            {
                lastSlidePart = (SlidePart)presentationPart.GetPartById(prevSlideId.RelationshipId);
            }
            else
            {
                lastSlidePart = (SlidePart)presentationPart.GetPartById(((SlideId)(slideIdList.ChildElements[0])).RelationshipId);
            }

            // Use the same slide layout as that of the previous slide.
            if (null != lastSlidePart.SlideLayoutPart)
            {
                slidePart.AddPart(lastSlidePart.SlideLayoutPart);
            }

            // Insert the new slide into the slide list after the previous slide.
            SlideId newSlideId = slideIdList.InsertAfter(new SlideId(), prevSlideId);
            newSlideId.Id = maxSlideId;
            newSlideId.RelationshipId = presentationPart.GetIdOfPart(slidePart);

        }
        //Methode de remplissage de cellule dans un tableau
        static Drawing.TableCell CreateTextCell(string text)
        {
            Drawing.TableCell tc = new Drawing.TableCell(
                                new Drawing.TextBody(
                                    new Drawing.BodyProperties(), new Drawing.Paragraph(
                                    new Drawing.Run(new Drawing.Text(text)))),
                                new Drawing.TableCellProperties());
            return tc;
        }

        private static void CREATE_OUTPUT_DOC(SPWeb web, Stream outputStream, string filename, string ext)
        {
            try
            {
                SPList outputLibrary = web.Lists.TryGetList("Documents");
                if (outputLibrary != null)
                {
                    string outputFileUrl = string.Format("{0}/{1}", outputLibrary.RootFolder.ServerRelativeUrl, filename + ext);
                    web.AllowUnsafeUpdates = true;
                    outputLibrary.RootFolder.Files.Add(outputFileUrl, outputStream);
                    web.Update();
                    if (outputStream != null)
                    {
                        outputStream.Dispose();
                    }
                    Console.WriteLine("Le Document a bien été généré\n");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Erreur de création de Document\n :" + ex.ToString());
            }
        }
    }
}

